namespace WP7Contrib.Services.BingMaps.Model
{
    using System.Device.Location;
    using Common;
    using Common.Extensions;
    using Microsoft.Phone.Controls.Maps;
    using Collections;

    public class RouteSearchResult : Result, ICloneable<RouteSearchResult>
    {
        private LocationRect boundingBox;
        private string distanceUnit;
        private string durationUnit;
        private double? travelDistance;
        private double? travelDuration;
        private int estimatedTotal;

        private LocationCollection points;
        private ObservableCollection<RouteLeg> routeLegs;

        public RouteSearchResult()
            : base()
        {
            this.points = new LocationCollection();
            this.routeLegs = new ObservableCollection<RouteLeg>();
        }

        public LocationRect BoundingBox
        {
            get
            {
                return this.boundingBox;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.boundingBox, value, () => this.BoundingBox);
            }
        }

        public string DistanceUnit
        {
            get
            {
                return this.distanceUnit;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.distanceUnit, value, () => this.DistanceUnit);
            }
        }

        public string DurationUnit
        {
            get
            {
                return this.durationUnit;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.durationUnit, value, () => this.DurationUnit);
            }
        }

        public double? TravelDistance
        {
            get
            {
                return this.travelDistance;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.travelDistance, value, () => this.TravelDistance);
            }
        }

        public double? TravelDuration
        {
            get
            {
                return this.travelDuration;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.travelDuration, value, () => this.TravelDuration);
            }
        }

        public ObservableCollection<RouteLeg> RouteLegs
        {
            get
            {
                return this.routeLegs;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.routeLegs, value, () => this.RouteLegs);
            }
        }
        
        public int EstimatedTotal
        {
            get
            {
                return this.estimatedTotal;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.estimatedTotal, value, () => this.EstimatedTotal);
            }
        }

        public LocationCollection Points
        {
            get
            {
                return this.points;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.points, value, () => this.Points);
            }
        }

        public bool HasRouteLegs
        {
            get { return this.routeLegs != null && this.routeLegs.Count != 0; }
        } 

        public bool HasSingleRouteLeg
        {
            get { return this.HasRouteLegs && this.routeLegs.Count == 1; }
        }

        public bool HasMultipleRouteLegs
        {
            get { return this.HasRouteLegs && this.routeLegs.Count > 1; }
        } 

        public bool HasPoints
        {
            get { return this.points != null && this.points.Count != 0; }
        }

        public bool HasBoundingBox
        {
            get { return this.boundingBox != null; }
        }

        public RouteSearchResult ShallowClone()
        {
            var result = new RouteSearchResult
            {
                BoundingBox = this.boundingBox,
                DistanceUnit = this.distanceUnit,
                DurationUnit = this.durationUnit,
                TravelDistance = this.travelDistance,
                TravelDuration = this.travelDuration,
                EstimatedTotal = this.estimatedTotal,
                Points = this.points,
                RouteLegs =  this.routeLegs
            };

            result.CloneBaseResult(this);
            return result;
        }

        public RouteSearchResult DeepClone()
        {
            var result = new RouteSearchResult
            {
                DistanceUnit = this.distanceUnit,
                DurationUnit = this.durationUnit,
                TravelDistance = this.travelDistance,
                TravelDuration = this.travelDuration,
                EstimatedTotal = this.estimatedTotal,
            };

            if (this.HasBoundingBox)
                result.BoundingBox = new LocationRect(this.boundingBox.North, this.boundingBox.West, this.boundingBox.South, this.boundingBox.East);

            if (this.HasPoints)
            {
                var copy = new LocationCollection();
                this.points.ForEach(p => copy.Add(new GeoCoordinate(p.Latitude, p.Longitude)));

                result.Points = copy;
            }

            if (this.HasRouteLegs)
            {
                var copy = new ObservableCollection<RouteLeg>();
                this.routeLegs.ForEach(r => copy.Add(r.DeepClone()));

                result.RouteLegs = copy;
            }

            result.CloneBaseResult(this);
            return result;
        }
    }
}